﻿// -
// <copyright file="AdmAuthClientIdentity.cs" company="Microsoft Corporation">
//    Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// -
namespace Microsoft.Hawaii
{
    using System;
    using System.Collections.Generic;
    using System.Security;

    /// <summary>
    /// The adm authentication client identity.
    /// </summary>
    public class AdmAuthClientIdentity : ClientIdentity
    {
        /// <summary>
        /// Specifies the adm OAuth service endpoint.
        /// </summary>
        private const string AdmOAuthEndpoint = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";

        /// <summary>
        /// The name of the config file that indicates what is the service scope. Used only as a test hook.
        /// All the hawaii services share one single service scope.
        /// </summary>
        private static readonly string StagingServiceScopeConfigFileName = @"C:\AzureStagingDeploymentConfig\HawaiiServiceScopeConfig.ini";

        /// <summary>
        /// A dictionary mapping clientids to tokenservice instances
        /// </summary>
        private static Dictionary<string, AdmTokenService> tokenServices = new Dictionary<string, AdmTokenService>();

        /// <summary>
        /// The adm token service instance.
        /// </summary>
        private AdmTokenService tokenService;

        /// <summary>
        /// The adm client Id.
        /// </summary>
        private string clientId;

        /// <summary>
        /// The adm client secret.
        /// </summary>
        private string clientSecret;

        /// <summary>
        /// The adm service scope.
        /// </summary>
        private string scope;

        /// <summary>
        /// Initializes a new instance of the AdmAuthClientIdentity class.
        /// </summary>
        /// <param name="clientId">The adm client Id.</param>
        /// <param name="clientSecret">The adm client secret.</param>
        /// <param name="scope">The scope Uri.</param>
        public AdmAuthClientIdentity(string clientId, string clientSecret, string scope) :
            this(clientId, clientSecret, scope, string.Empty, string.Empty)
        {
        }

        /// <summary>
        /// Initializes a new instance of the AdmAuthClientIdentity class.
        /// </summary>
        /// <param name="clientId">The adm client Id.</param>
        /// <param name="clientSecret">The adm client secret.</param>
        /// <param name="scope">The scope Uri.</param>
        /// <param name="registrationId">The registration Id.</param>
        /// <param name="secretKey">The secret key.</param>
        public AdmAuthClientIdentity(string clientId, string clientSecret, string scope, string registrationId, string secretKey) :
            base(registrationId, secretKey)
        {
            this.clientId = clientId;
            this.clientSecret = clientSecret;
            this.scope = scope;

            lock (tokenServices)
            {
                if (!tokenServices.TryGetValue(clientId, out this.tokenService))
                {
                    this.tokenService = new AdmTokenService(
                        clientId,
                        clientSecret,
                        AdmOAuthEndpoint,
                        scope);

                    tokenServices.Add(clientId, this.tokenService);
                }
            }
        }

        /// <summary>
        /// Gets the Adm client Id.
        /// </summary>
        public string ClientId
        {
            get
            {
                return this.clientId;
            }
        }

        /// <summary>
        /// Returns the service scope to be used when accessing the adm OAuth service. This will generally
        /// be the value generated by the DefaultServiceScope, but it can conditionally be set with
        /// the presence of a config file on first access.
        /// </summary>
        /// <param name="serviceBaseUri">The target service base Uri.</param>
        /// <returns>Returns the service scope</returns>
        [SecuritySafeCritical]
        public static string GetServiceScope(string serviceBaseUri)
        {
            UriBuilder uriBuilder = new UriBuilder(serviceBaseUri);
            string defaultServiceScope = string.Format("{0}://{1}", uriBuilder.Scheme, uriBuilder.Host);

            return ClientLibraryUtils.LookupServiceScopeFromConfig(StagingServiceScopeConfigFileName, defaultServiceScope);
        }

        /// <summary>
        /// Override the method to copy Adm authentication identity
        /// </summary>
        /// <returns>Returns the client identity</returns>
        public override ClientIdentity Copy()
        {
            return new AdmAuthClientIdentity(this.clientId, this.clientSecret, this.scope, this.RegistrationId, this.SecretKey);
        }

        /// <summary>
        /// Override the method to retrive the access token for Adm authentication.
        /// </summary>
        /// <param name="callback">event callback</param>
        public override void RetriveAccessToken(RetriveAccessTokenComplete callback)
        {
            this.tokenService.GetAccessToken(new AdmTokenService.RetriveAdmAccessTokenComplete((accessToken, ex) =>
                {
                    TokenService_GetAdmAccessTokenCompleteEvent(accessToken, ex, callback);
                }));
        }

        /// <summary>
        /// The callback handler of GetAdmAccessToken event of AdmTokenService.
        /// </summary>
        /// <param name="accessToken">The token instance.</param>
        /// <param name="ex">Coressponding exception if failed to get the access token.</param>
        /// <param name="callback">callback from event</param>
        private void TokenService_GetAdmAccessTokenCompleteEvent(AdmAccessToken accessToken, Exception ex, RetriveAccessTokenComplete callback)
        {
            if (ex == null)
            {
                string token = string.Empty;

                if (!string.IsNullOrEmpty(this.RegistrationId) &&
                    !string.IsNullOrEmpty(this.SecretKey))
                {
                    token = string.Format("BEARER {0} {1} {2}", accessToken.AccessToken, this.SecretKey, this.RegistrationId);
                }
                else
                {
                    token = string.Format("BEARER {0}", accessToken.AccessToken);
                }

                this.OnRetriveAccessTokenComplete(token, ex, callback);
            }
            else
            {
                this.OnRetriveAccessTokenComplete(string.Empty, ex, callback);
            }
        }
    }
}